#ifndef NetChannel_H
#define NetChannel_H

#include "EspressifMQTTClient.cpp"
#include "Helper.h"
#include "IMQTTClient.h"
#include "RemoteConfig.h"
#include "convert.h"
#include "Profile.h"
#define TAG "NetChannel"
#define THINGSBOARD_RPC_RESPONSE "v1/devices/me/rpc/response/%s"
#define MQTT_RESPONSE_BODY "{\"status\":%d}"

typedef enum {
	TCP,
	UDP,
	MQTT,
	HTTP
} NetProtocol;

class NetChannel {
public:
	NetChannel(const dtu_config_t *dtu_config) :
		m_dtu_config(dtu_config) {}
	~NetChannel() {}
	/**
	 * 初始化网络通道
	 */
	void init_channel() {
		Helper::generateDeviceId(imei);

		for (size_t i = 0; i < 1; i++) {
			const network_channel_t *channel = &m_dtu_config->network_channels[i];
			if (m_dtu_config->data_templates[i].enable) {
				m_conver[i] = new Convert();
			}
			NetProtocol protocol = netWorkType(channel->type);
			switch (protocol) {
			case MQTT:
				initMqttChannel(i);
				break;

			default:
				ESP_LOGE(TAG, "init channel network protocol not found %d", protocol);
				break;
			}
		}
	}

	void sendData(uint8_t channel_num, char const *payload, size_t const &length) {
		const network_channel_t *channel = &m_dtu_config->network_channels[channel_num];
		const data_template_t *data_temp = &m_dtu_config->data_templates[channel_num];
		const char *send_ptr = payload;
		size_t send_len = length;
		char *conver_data = nullptr;
		// 数据转换
		if (data_temp->enable) {
			conver_data = m_conver[channel_num]->lua_convert("sendData", data_temp->send_template, payload, length);
			send_ptr = conver_data;
			send_len = strlen(conver_data);
		}

		if (netWorkType(channel->type) == MQTT) {
			if (!m_client[channel_num]->connected()) {
				return;
			}
			const network_channel_mqtt_t *mqtt_channel = &m_dtu_config->network_channel_mqtts[channel_num];
			m_client[channel_num]->publish(mqtt_channel->publish_topic, send_ptr, send_len, mqtt_channel->publish_qos, false);
		}

		if (conver_data) {
			free(conver_data);
		}
	}

	/**
	 * 设置数据回调事件
	 * Callback<std::vector<uint8_t>, uint8_t, std::vector<uint8_t>
	 * 通道号
	 * 消息体
	 * 返回 std::vector<uint8_t>
	 *
	 */
	void setDataCallback(Callback<unsigned int, uint8_t, char *, size_t>::function callback) {
		this->onDataCallback.setCallback([this, callback](uint8_t channel_num, char *payload, unsigned int len) {
			const data_template_t *data_temp = &this->m_dtu_config->data_templates[channel_num];
			char *send_ptr = payload;
			size_t send_len = len;
			char *conver_data = nullptr;
			if (data_temp->enable) {
				conver_data = m_conver[channel_num]->lua_convert("receiveData", data_temp->receive_template, send_ptr, send_len);
				send_ptr = conver_data;
				send_len = strlen(conver_data);
			}
			const network_channel_t *channel = &this->m_dtu_config->network_channels[channel_num];
			unsigned int status = callback(channel->bound_serial, send_ptr, send_len);
			if (conver_data) {
				free(conver_data);
			}
			return status;
		});
	}

private:
	NetProtocol netWorkType(int type) {
		if (type == 2 || type == 10) {
			return MQTT;
		}
		return HTTP;
	}

	void onMQTTMessage(char *topic, uint8_t *payload, unsigned int length, IMQTTClient *m_mqtt_client, int channel_num) {
		std::vector<char> buf(payload, payload + length);
		ESP_LOGI(TAG, "Received MQTT message: Topic: %s Payload (hex): %.*s Length: %u", topic, length, payload, length);

		const network_channel_t *channel = &this->m_dtu_config->network_channels[channel_num];
		// MQTT = 2 thingsboard = 10
		if (netWorkType(channel->type) == MQTT) {
			unsigned int rsult = this->onDataCallback.callCallback(channel_num, (char *)payload, length);
			char buf[64];
			snprintf(buf, sizeof(buf), MQTT_RESPONSE_BODY, rsult);
			if (channel->type == 10) {
				thingsboardRpcRequest(topic, m_mqtt_client, buf, rsult);
			}
		}
	}

	/**
	 * Thingsboard Rpc 需要回复
	 */
	void thingsboardRpcRequest(char *topic, IMQTTClient *m_mqtt_client, char *buf, int rsult) {
		// 获取requestId
		char *requestId = strrchr(topic, '/') + 1;
		char responseTopic[Helper::detectSize(THINGSBOARD_RPC_RESPONSE, requestId)] = {};
		(void)snprintf(responseTopic, sizeof(responseTopic), THINGSBOARD_RPC_RESPONSE, requestId);
		// 回复RPC请求
		int qos = this->m_dtu_config->network_channel_mqtts->publish_qos;
		m_mqtt_client->publish(responseTopic, buf, strlen(buf), qos, true);
	}

	void initMqttChannel(int i) {

		const network_channel_t *channel = &m_dtu_config->network_channels[i];
		const network_channel_mqtt_t *mqtt_channel = &m_dtu_config->network_channel_mqtts[i];
		this->m_client[i] = new EspressifMQTTClient();
		IMQTTClient *m_mqtt_client = this->m_client[i];
		// 设置MQTT服务
		m_mqtt_client->setServer(channel->server_address, channel->server_port);
		const char *sub_topic = mqtt_channel->subscribe_topic;
		// 连接MQTT服务
		m_mqtt_client->connect(imei, mqtt_channel->username, mqtt_channel->password);

		// 设置数据回调函数
		m_mqtt_client->setDataCallback([this, m_mqtt_client, i](char *topic, uint8_t *payload, unsigned int length) {
			// 进一步转发回调
			this->onMQTTMessage(topic, payload, length, m_mqtt_client, i);
		});

		// 设置连接回调
		uint16_t qos = mqtt_channel->subscribe_qos;
		m_mqtt_client->setConnectCallback([m_mqtt_client, sub_topic, qos] {
			// 连接成功后，先取消订阅在订阅
			m_mqtt_client->unsubscribe(sub_topic);
			m_mqtt_client->subscribe(sub_topic, qos);
		});
	}
	Callback<unsigned int, uint8_t, char *, unsigned int> onDataCallback;
	IMQTTClient *m_client[2];
	char imei[16];
	Convert *m_conver[2];
	const dtu_config_t *m_dtu_config;
};
#endif